Populate service map when bootstrap is skipped (e.g. under Rector)#996
Open
bbrala wants to merge 1 commit into
Open
Populate service map when bootstrap is skipped (e.g. under Rector)#996bbrala wants to merge 1 commit into
bbrala wants to merge 1 commit into
Conversation
The service map is built by DrupalAutoloader::register(), which runs as a bootstrapFiles entry. PHPStan executes those via CommandHelper. Tools that build the PHPStan container directly (Rector's PHPStanServicesFactory) never call CommandHelper, so the bootstrap is skipped and the map stays empty — \Drupal::service() then resolves to object instead of the concrete class. Register a guarded, eagerly-instantiated no-op return type extension that runs the autoloader against the live container when the map is still empty. A normal phpstan analyse run stays a no-op because the bootstrap already filled the map. Refs mglaman#995
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #995.
The service map is built by
DrupalAutoloader::register(), which runs as abootstrapFilesentry. PHPStan executes those throughCommandHelper::executeBootstrapFile(). Tools that build the PHPStan container directly never callCommandHelper, so the bootstrap is skipped and the map stays empty. Rector is the case — itsPHPStanServicesFactorycallsContainerFactory::create()and stops there — so\Drupal::service('renderer')resolves toobjectinstead ofDrupal\Core\Render\Renderer, and type-aware Rector rules silently skip those nodes.This registers
RectorServiceMapInitializer, a no-opDynamicStaticMethodReturnTypeExtensionthat PHPStan instantiates eagerly when the broker builds. If the service map is still empty at that point, it runs the autoloader against the live container. The empty-map guard keeps a normalphpstan analyserun a no-op, since the bootstrap already populated the map there.I went with reusing
DrupalAutoloader::register()wholesale rather than refactoring the scan out of it, to keep the change small. Lazy population insideServiceMapwould be cleaner as the real shape if you'd prefer that — happy to rework.Tested against Drupal 11 with Rector 2.4 across a full install (webform, photoswipe):
\Drupal::service('renderer')resolves toRendererand\Drupal::service('entity_type.manager')toEntityTypeManager, Rector processes both modules without errors, and standalonephpstan analysebehaves exactly as before.Claude was used for research and development of this issue and fix.